#include "stdafx.h"
#include "Maths.h"
#include "BagOfTasks.h"
#include "MeshesParser.h"
#include "KdTree.h"
#include "SceneObject.h"

struct Task
{
	int startRange;
	int endRange;
	int *outputArray;
	int threadIndex;
	bool *confirmArray;

	explicit Task(int start, int end, int index,int *output, bool *boolArray) : startRange(start) , endRange(end), outputArray(output), threadIndex(index), confirmArray(boolArray){}
};

template <typename T>
struct OutputStruct
{
	//RecursiveRayTracer<T> *rec;
	int totalRange;
	int *output;
	bool *confitmArray;
	OutputStruct(int size, int *outputArray, bool *confirmArray) : totalRange(size) , output(outputArray), confitmArray(confirmArray){}
};

template<typename T> 
 class RecursiveRayTracer
{
public:
	#define M_PI  3.141592653589793
	#define MAX_RAY_DEPTH 5


	#pragma region simple raytracer
	//// This is the main trace function. It takes a ray as argument (defined by its origin
	//// and direction). We test if this ray intersects any of the geometry in the scene.
	//// If the ray intersects an object, we compute the intersection point, the normal
	//// at the intersection point, and shade this point using this information.
	//// Shading depends on the surface property (is it transparent, reflective, diffuse).
	//// The function returns a color for the ray. If the ray intersects an object that
	//// is the color of the object at the intersection point, otherwise it returns
	//// the background color.
	static Vec3<T> trace( Vec3<T> &rayorig,  Vec3<T> &raydir
		, const std::vector<Sphere<T> *> &spheres, const int &depth)
	{
		//if (raydir.length() != 1) std::cerr << "Error " << raydir << std::endl;
		T tnear = INFINITY;
		const Sphere<T> *sphere = NULL;
		// find intersection of this ray with the sphere in the scene
		for (unsigned i = 0; i < spheres.size(); ++i) {
			T t0 = INFINITY, t1 = INFINITY;
			Sphere<T> *currentSphere = spheres[i];
			if (currentSphere->intersect(rayorig, raydir, &t0, &t1)) 
			{
				if (t0 < 0) t0 = t1;
				if (t0 < tnear) {
					tnear = t0;
					sphere = spheres[i];
				}
			}
		}
		// if there's no intersection return black or background color
		if (sphere == NULL) return Vec3<T>(2);		
		
		Vec3<T> surfaceColor = 0; // color of the ray/surfaceof the object intersected by the ray
		Vec3<T> phit = rayorig + raydir * tnear; // point of intersection
		Vec3<T> nhit = phit - sphere->center; // normal at the intersection point
		nhit.normalize(); // normalize normal direction
		// If the normal and the view direction are not opposite to each other 
		// reverse the normal direction. That also means we are inside the sphere so set
		// the inside bool to true. Finally reverse the sign of IdotN which we want
		// positive.
		T bias = 1e-4; // add some bias to the point from which we will be tracing
		bool inside = false;
		if (raydir.dot(nhit) > 0) nhit = -nhit, inside = true;
		if ((sphere->transparency > 0 || sphere->reflection > 0) && depth < MAX_RAY_DEPTH) {
			T facingratio = -raydir.dot(nhit);
			// change the mix value to tweak the effect
			T fresneleffect =  RecursiveRayTracer<float>::mix(pow(1 - facingratio, 3), 1, 0.1); 
			// compute reflection direction (not need to normalize because all vectors
			// are already normalized)
			Vec3<T> refldir = raydir - nhit * 2 * raydir.dot(nhit);
			refldir.normalize();
			Vec3<T> reflection = RecursiveRayTracer<T>::trace(phit + nhit * bias, refldir, spheres, depth + 1);
			Vec3<T> refraction = 0;
			// if the sphere is also transparent compute refraction ray (transmission)
			if (sphere->transparency) {
				T ior = 1.1, eta = (inside) ? ior : 1 / ior; // are we inside or outside the surface?
				T cosi = -nhit.dot(raydir);
				T k = 1 - eta * eta * (1 - cosi * cosi);
				Vec3<T> refrdir = raydir * eta + nhit * (eta *  cosi - sqrt(k));
				refrdir.normalize();
				refraction = RecursiveRayTracer<T>::trace(phit - nhit * bias, refrdir, spheres, depth + 1);
			}
			// the result is a mix of reflection and refraction (if the sphere is transparent)
			surfaceColor = (reflection * fresneleffect + 
				refraction * (1 - fresneleffect) * sphere->transparency) * sphere->surfaceColor;
		}
		else {
			// it's a diffuse object, no need to raytrace any further
			for (unsigned i = 0; i < spheres.size(); ++i) {
				if (spheres[i]->emissionColor.x > 0) {
					// this is a light
					Vec3<T> transmission = 1;
					Sphere<T> *currentSphere = spheres[i];
					Vec3<T> lightDirection = currentSphere->center - phit;
					lightDirection.normalize();
					for (unsigned j = 0; j < spheres.size(); ++j) {
						if (i != j) {
							T t0, t1;
							if (spheres[j]->intersect(phit + nhit * bias, lightDirection, &t0, &t1)) {
								transmission = 0;
								break;
							}
						}
					}
					surfaceColor += sphere->surfaceColor * transmission * std::max(T(0), nhit.dot(lightDirection)) * spheres[i]->emissionColor;
				}
			}
		}

		return surfaceColor + sphere->emissionColor;
	}
	#pragma endregion simplest raytracer found online


	static Vec3<T> trace(Vec3<T> &rayorig, Vec3<T> &raydir,const int &depth, vector<GenericObject<T>*> allObjects)
	{
		//if (raydir.length() != 1) std::cerr << "Error " << raydir << std::endl;
		T tnear = INFINITY;
		GenericObject<T> *intersectingObject = NULL;
		Triangle<T> * intersectingTrinagle = NULL;
		Vec3<T> *intersectionPoint = NULL;
		// find intersection of this ray with the sphere in the scene
		for (unsigned i = 0; i < allObjects.size(); ++i) {
			T t0 = INFINITY, t1 = INFINITY;
			GenericObject<T> *currentObject = allObjects[i];
			if(currentObject->objectType == 0)
			{
				if (currentObject->intersect(rayorig, raydir, t0, t1)) 
				{	
					if(t0 < 0) t0 = t1;
					tnear = t0;
					intersectingObject = currentObject;
					break;
				}
			}
			else 
			{
				if(currentObject->GetRayIntersection(rayorig, raydir, intersectingTrinagle))
				{
					t0 = intersectingTrinagle->GetDistanceIntersection(rayorig, raydir);
					cout<<"found intersection :)" << endl;
					tnear = t0;
					intersectingObject = currentObject;
					break;
				}
			}

			
			
		}


		// if there's no intersection return black or background color
		if (intersectingObject == NULL) 
		{
			return Vec3<T>(2);
		}

		Vec3<T> surfaceColor = 0; // color of the ray/surfaceof the object intersected by the ray
		Vec3<T> phit = rayorig + raydir * tnear; // point of intersection
		Vec3<T> nhit = intersectingObject->objectType == 0 ? intersectingObject->GetIntersectionPointNormal(rayorig, raydir, tnear): intersectingTrinagle->GetTriangleNormal(); //normal
		nhit.normalize(); // normalize normal direction
		// If the normal and the view direction are not opposite to each other 
		// reverse the normal direction. That also means we are inside the sphere so set
		// the inside bool to true. Finally reverse the sign of IdotN which we want
		// positive.
		T bias = 1e-4; // add some bias to the point from which we will be tracing
		bool inside = false;
		if (raydir.dot(nhit) > 0) nhit = -nhit, inside = true;
		
		if ((intersectingObject->transparency > 0 || intersectingObject->reflection > 0) && depth < MAX_RAY_DEPTH) 
		{
			int next = depth + 1;
			T facingratio = -raydir.dot(nhit);
			// change the mix value to tweak the effect
			T fresneleffect =  RecursiveRayTracer<float>::mix(pow(1 - facingratio, 3), 1, 0.1); 
			// compute reflection direction (not need to normalize because all vectors
			// are already normalized)
			Vec3<T> refldir = raydir - nhit * 2 * raydir.dot(nhit);
			refldir.normalize();
			//////////////////////here
			Vec3<T> reflection = RecursiveRayTracer<T>::trace(phit + nhit * bias, refldir, next, allObjects);
			Vec3<T> refraction = 0;
			// if the sphere is also transparent compute refraction ray (transmission)
			if (intersectingObject->transparency > 0) {
				T ior = 1.1, eta = (inside) ? ior : 1 / ior; // are we inside or outside the surface?
				T cosi = -nhit.dot(raydir);
				T k = 1 - eta * eta * (1 - cosi * cosi);
				Vec3<T> refrdir = raydir * eta + nhit * (eta *  cosi - sqrt(k));
				refrdir.normalize();
				refraction = RecursiveRayTracer<T>::trace(phit + nhit * bias, refrdir, next, allObjects);
			}
			// the result is a mix of reflection and refraction (if the sphere is transparent)
			surfaceColor = (reflection * fresneleffect + 
				refraction * (1 - fresneleffect) * intersectingObject->transparency) * intersectingObject->surfaceColor;
			
			/*if(myFile.is_open())
			{
				myFile << refraction.x << "," << refraction.y << "," << refraction.z << ":" << depth<< "\n";
			}*/
		}
		else {
			// it's a diffuse object, no need to raytrace any further
			for (unsigned i = 0; i < allObjects.size(); ++i) {
				if (allObjects[i]->emissionColor.x > 0) {
					// this is a light
					Vec3<T> transmission = 1;
					GenericObject<T> *currentLight = allObjects[i];
					Vec3<T> lightDirection =  currentLight->center - phit;
					lightDirection.normalize();
					for (unsigned j = 0; j < allObjects.size(); ++j) {
						if (i != j) {
							T t0, t1;
							if (allObjects[j]->intersect(phit + nhit * bias, lightDirection, t0, t1)) {
								transmission = 0;
								break;
							}
						}
					}
					Vec3<T> amoountOfShader = (intersectingObject->surfaceColor * transmission * max(T(0), (nhit.x * lightDirection.x + nhit.y * lightDirection.y + nhit.z * lightDirection.z)) * currentLight->emissionColor);

					/*if(myFile.is_open())
					{
						myFile << amoountOfShader.x << "," << amoountOfShader.y << "," << amoountOfShader.z << ":" << depth<< "\n";
					}*/

					surfaceColor += amoountOfShader;
				}
			}
		}

		return surfaceColor + intersectingObject->emissionColor;
	}

	static Vec3<T> trace(Vec3<T> &rayorig, Vec3<T> &raydir, vector<Sphere<T> *> &spheres, const int &depth)
	{
		//if (raydir.length() != 1) std::cerr << "Error " << raydir << std::endl;
		T tnear = INFINITY;
		const Sphere<T> *sphere = NULL;
		// find intersection of this ray with the sphere in the scene
		for (unsigned i = 0; i < spheres.size(); ++i) {
			T t0 = INFINITY, t1 = INFINITY;
			Sphere<T> *currentSphere = spheres[i];
			if (currentSphere->intersect(rayorig, raydir, &t0, &t1)) 
			{
				if (t0 < 0) t0 = t1;
				if (t0 < tnear) {
					tnear = t0;
					sphere = spheres[i];
				}
			}
		}


		// if there's no intersection return black or background color
		if (sphere == NULL) 
		{
			return Vec3<T>(2);		
		}

		Vec3<T> surfaceColor = 0; // color of the ray/surfaceof the object intersected by the ray
		Vec3<T> phit = rayorig + raydir * tnear; // point of intersection
		Vec3<T> nhit = phit - sphere->center; // normal at the intersection point
		nhit.normalize(); // normalize normal direction
		// If the normal and the view direction are not opposite to each other 
		// reverse the normal direction. That also means we are inside the sphere so set
		// the inside bool to true. Finally reverse the sign of IdotN which we want
		// positive.
		T bias = 1e-4; // add some bias to the point from which we will be tracing
		bool inside = false;
		if (raydir.dot(nhit) > 0) nhit = -nhit, inside = true;
		if ((sphere->transparency > 0 || sphere->reflection > 0) && depth < MAX_RAY_DEPTH) {
			T facingratio = -raydir.dot(nhit);
			// change the mix value to tweak the effect
			T fresneleffect =  RecursiveRayTracer<float>::mix(pow(1 - facingratio, 3), 1, 0.1); 
			// compute reflection direction (not need to normalize because all vectors
			// are already normalized)
			Vec3<T> refldir = raydir - nhit * 2 * raydir.dot(nhit);
			refldir.normalize();
			Vec3<T> reflection = RecursiveRayTracer<T>::trace(phit + nhit * bias, refldir, spheres, depth + 1);
			Vec3<T> refraction = 0;
			// if the sphere is also transparent compute refraction ray (transmission)
			if (sphere->transparency) {
				T ior = 1.1, eta = (inside) ? ior : 1 / ior; // are we inside or outside the surface?
				T cosi = -nhit.dot(raydir);
				T k = 1 - eta * eta * (1 - cosi * cosi);
				Vec3<T> refrdir = raydir * eta + nhit * (eta *  cosi - sqrt(k));
				refrdir.normalize();
				refraction = RecursiveRayTracer<T>::trace(phit - nhit * bias, refrdir, spheres, depth + 1);
			}
			// the result is a mix of reflection and refraction (if the sphere is transparent)
			surfaceColor = (reflection * fresneleffect + 
				refraction * (1 - fresneleffect) * sphere->transparency) * sphere->surfaceColor;
		}
		else {
			// it's a diffuse object, no need to raytrace any further
			for (unsigned i = 0; i < spheres.size(); ++i) {
				if (spheres[i]->emissionColor.x > 0) {
					// this is a light
					Vec3<T> transmission = 1;
					Sphere<T> *currentSphere = spheres[i];
					Vec3<T> lightDirection = currentSphere->center - phit;
					lightDirection.normalize();
					for (unsigned j = 0; j < spheres.size(); ++j) {
						if (i != j) {
							T t0, t1;
							if (spheres[j]->intersect(phit + nhit * bias, lightDirection, &t0, &t1)) {
								transmission = 0;
								break;
							}
						}
					}
					surfaceColor += sphere->surfaceColor * transmission * max(T(0), nhit.dot(lightDirection)) * spheres[i]->emissionColor;
				}
			}
		}

		return surfaceColor + sphere->emissionColor;
	}


	static T mix(const T &a, const T &b, const T &mix)
	{
		return b * mix + a * (T(1) - mix);
	}

	static void render(vector<Sphere<T> *> &spheres)
	{
		unsigned width = 640, height = 480;
		Vec3<T> *image = new Vec3<T>[width * height], *pixel = image;
		T invWidth = 1 / T(width), invHeight = 1 / T(height);
		T fov = 30, aspectratio = width / T(height);
		T angle = tan(M_PI * 0.5 * fov / T(180));

		std::ofstream myFile("spheres.txt");
		// Trace rays
		for (unsigned y = 0; y < height; ++y) {
			for (unsigned x = 0; x < width; ++x, ++pixel) {
				T xx = (2 * ((x + 0.5) * invWidth) - 1) * angle * aspectratio;
				T yy = (1 - 2 * ((y + 0.5) * invHeight)) * angle;
				//changed from -1 to 1
				Vec3<T> rayDir(xx, yy, -1);
				rayDir.normalize();
				Vec3<T> output = RecursiveRayTracer<T>::trace(Vec3<T>(0), rayDir, spheres, 0);
				*pixel =  output;
				myFile << output.x << "," << output.y << "," << output.z << "\n";
				
			}
		}
		// Save result to a PPM image (keep these flags if you compile under Windows)
		std::ofstream ofs("./untitled.ppm", std::ios::out | std::ios::binary);
		ofs << "P6\n" << width << " " << height << "\n255\n";
		for (unsigned i = 0; i < width * height; ++i) {
			ofs << (unsigned char)(min(T(1), image[i].x) * 255) << 
			(unsigned char)(min(T(1), image[i].y) * 255) <<
			(unsigned char)(min(T(1), image[i].z) * 255); 
		}
		ofs.close();
		myFile.close();
		delete [] image;
	}



	//static void render(vector<Sphere<T> *> &spheres, Plane<T> &floor, vector<GenericObject<T>> allObjects,vector<Sphere<T> *> light)
	//{
	//	unsigned width = 640, height = 480;
	//	Vec3<T> *image = new Vec3<T>[width * height], *pixel = image;
	//	T invWidth = 1 / T(width), invHeight = 1 / T(height);
	//	T fov = 30, aspectratio = width / T(height);
	//	T angle = tan(M_PI * 0.5 * fov / T(180));
	//	// Trace rays
	//	for (unsigned y = 0; y < height; ++y) {
	//		for (unsigned x = 0; x < width; ++x, ++pixel) {
	//			T xx = (2 * ((x + 0.5) * invWidth) - 1) * angle * aspectratio;
	//			T yy = (1 - 2 * ((y + 0.5) * invHeight)) * angle;
	//			Vec3<T> rayDir(xx, yy, -1);
	//			rayDir.normalize();
	//			*pixel =  RecursiveRayTracer<T>::trace(Vec3<T>(0), rayDir, 0,floor, allObjects, light);
	//			
	//		}
	//	}
	//	// Save result to a PPM image (keep these flags if you compile under Windows)
	//	std::ofstream ofs("./untitled.ppm", std::ios::out | std::ios::binary);
	//	ofs << "P6\n" << width << " " << height << "\n255\n";
	//	for (unsigned i = 0; i < width * height; ++i) {
	//		ofs << (unsigned char)(std::min(T(1), image[i].x) * 255) << 
	//		(unsigned char)(std::min(T(1), image[i].y) * 255) <<
	//		(unsigned char)(std::min(T(1), image[i].z) * 255); 
	//	}
	//	ofs.close();
	//	delete [] image;
	//}

	static void render(vector<GenericObject<T>*> allObjects)
	{
	unsigned width = 600, height = 400;
		Vec3<T> *image = new Vec3<T>[width * height], *pixel = image;
		T invWidth = 1 / T(width), invHeight = 1 / T(height);
		T fov = 30, aspectratio = width / T(height);
		T angle = tan(M_PI * 0.5 * fov / T(180));
		std::ofstream myFile("./genericObjects.txt");
		
		// Trace rays
		for (unsigned y = 0; y < height; ++y) {
			for (unsigned x = 0; x < width; ++x, ++pixel) {
				T xx = (2 * ((x + 0.5) * invWidth) - 1) * angle * aspectratio;
				T yy = (1 - 2 * ((y + 0.5) * invHeight)) * angle;
				//changed from -1 to 1
				Vec3<T> rayDir(xx, yy, -1);
				rayDir.normalize();

				Vec3<T> output1 =  RecursiveRayTracer<T>::trace(Vec3<T>(0), rayDir,0, allObjects);
				//Vec3<T> output2 = RecursiveRayTracer<T>::trace(Vec3<T>(0), rayDir,spheres,0);

				*pixel = output1;
			}
		}
		

		myFile.close();
		// Save result to a PPM image (keep these flags if you compile under Windows)
		//	std::ofstream ofs("./untitled.ppm", std::ios::out | std::ios::binary);
		//	ofs << "P6\n" << width << " " << height << "\n255\n";
		//	for (unsigned i = 0; i < width * height; ++i) {
		//		ofs << (unsigned char)(std::min(T(1), image[i].x) * 255) << 
		//		(unsigned char)(std::min(T(1), image[i].y) * 255) <<
		//		(unsigned char)(std::min(T(1), image[i].z) * 255); 
		//	}
		//	ofs.close();
	

		std::ofstream ofs("./dragon.ppm", std::ios::out | std::ios::binary);
		ofs << "P6\n" << width << " " << height << "\n255\n";
		for (unsigned i = 0; i < width * height; ++i) {
			ofs << (unsigned char)(min(T(1), image[i].x) * 255) << 
			(unsigned char)(min(T(1), image[i].y) * 255) <<
			(unsigned char)(min(T(1), image[i].z) * 255); 
		}
		ofs.close();
		delete [] image;
	}

	static void Execute(void)
	{
		srand(13);
		vector<GenericObject<float>*> objectList;
		time_t startTimer;
		time_t endTimer;
		
		time(&startTimer);
		//vector<Triangle<float>*> objectMesh = ObjectParser::ParseObjFile("C:\\Users\\adebarro\\Desktop\\dragon.obj",Vec3<float>(5, -1, -15) );
		time(&endTimer);
		
		std::cout << "elapsed time is : " << endTimer - startTimer << std::endl;
		/*	// position, radius, surface color, reflectivity, transparency|, emission color
		spheres.push_back(new Sphere<float>(Vec3<float>(0, -10004, -20), 10000, Vec3<float>(0.2), 0, 0.0));
		spheres.push_back(new Sphere<float>(Vec3<float>(0, 0, -20), 4, Vec3<float>(1.00, 0.32, 0.36), 1, 0.5));
		spheres.push_back(new Sphere<float>(Vec3<float>(5, -1, -15), 2, Vec3<float>(0.90, 0.76, 0.46), 1, 0.0));
		spheres.push_back(new Sphere<float>(Vec3<float>(5, 0, -25), 3, Vec3<float>(0.65, 0.77, 0.97), 1, 0.0));
		spheres.push_back(new Sphere<float>(Vec3<float>(-5.5, 0, -15), 3, Vec3<float>(0.90, 0.90, 0.90), 1, 0.0));
		light
		spheres.push_back(new Sphere<float>(Vec3<float>(0, 20, -30), 3, Vec3<float>(0), 0, 0, Vec3<float>(3)));
		*/

		//center,T radius, Vec3<T> surfaceColor, Vec3<T> emissonColor,T transparency , T reflection, int type)
		objectList.push_back(new GenericObject<float>(Vec3<float>(0, 0, -2), Vec3<float>(0.90, 0.76, 0.46),Vec3<float>(0), 0, 0.0, "C:\\Users\\Adrian\\Desktop\\dragon.obj"));
		objectList.push_back(new GenericObject<float>(Vec3<float>(0, -10004, -20), 10000, Vec3<float>(0.2),0, 0, 0.0,0));
		objectList.push_back(new GenericObject<float>(Vec3<float>(0, 0, -20), 4, Vec3<float>(1.00, 0.32, 0.36),1, 0.5,0));
		objectList.push_back(new GenericObject<float>(Vec3<float>(5, -1, -15), 2, Vec3<float>(0.90, 0.76, 0.46), 1, 0.0,0));
		objectList.push_back(new GenericObject<float>(Vec3<float>(5, 0, -25), 3, Vec3<float>(0.65, 0.77, 0.97), 1, 0.0,0));
		objectList.push_back(new GenericObject<float>(Vec3<float>(-5.5, 0, -15), 3, Vec3<float>(0.90, 0.90, 0.90), 1, 0.0, 0));
		//light
		objectList.push_back(new GenericObject<float>(Vec3<float>(0, 20, -30), 3, Vec3<float>(0), 0, 0.0,Vec3<float>(3),2));
		time(&startTimer);

		std::cout << "start time is " << startTimer << std::endl;
		RecursiveRayTracer<float>::render(objectList);
		
		time(&endTimer);
		std::cout << "End Time " << endTimer << std::endl;
		std::cout << "elapsed time is : " << endTimer - startTimer << std::endl;


		while (!objectList.empty()) {
			GenericObject<float> *sph = objectList.back();
			objectList.pop_back();
			delete sph;
		}

		/*while (!spheres.empty()) {
			Sphere<float> *sph = spheres.back();
			spheres.pop_back();
			delete sph;
		}*/
	}

	
	static void *ReturnedOutput(void *output)
	{
		BagOfTasksReply<float> *reply = (BagOfTasksReply<float>*)output;
		Vec3<float> *resultingOutput = (Vec3<float>*) reply->outputResult , *image = resultingOutput;
		
		std::ofstream ofs("./untitled.ppm", std::ios::out | std::ios::binary);
		ofs << "P6\n" << reply->width << " " << reply->height << "\n255\n";
		for (unsigned i = 0; i < reply->width * reply->height; ++i) {
			ofs << (unsigned char)(min(T(1), image[i].x) * 255) << 
			(unsigned char)(min(T(1), image[i].y) * 255) <<
			(unsigned char)(min(T(1), image[i].z) * 255); 
		}
		ofs.close();

		time_t endTimer;
		time(&endTimer);
		std::cout << "End Time " << endTimer << std::endl;

		delete [] image;
		return NULL;
		
		vector<Sphere<T>*> spheres = reply->spheres;

		while (!spheres.empty()) {
			Sphere<float> *sph = spheres.back();
			spheres.pop_back();
			delete sph;
		}
	
	}


	static void *ThreadExecute(void *task)
	{
		RecursiveRayTracingTask<float> *currentTask = (RecursiveRayTracingTask<float>*) task;
		//continue here

		vector<Sphere<T>*> spheres = currentTask->sphereListPointer;

		Vec3<T> *image = currentTask->outputColection;
		Vec3<T> *pixel = &image[currentTask->startRange];
		float invWidth = 1 / float(currentTask->width), invHeight = 1 / float(currentTask->height);
		float fov = 30, aspectratio = currentTask->width / float(currentTask->height);
		float angle = tan(M_PI * 0.5 * fov / float(180));
		int startingNumber = currentTask->startRange;
		// Trace rays
		//arrange this part

		bool firstTime = true;
		for (unsigned y = firstTime? currentTask->startingY : 0; y < currentTask->height; ++y) {
			for (unsigned x = firstTime?currentTask->startingX:0; x < currentTask->width; ++x, ++pixel) {
				if(firstTime)
				{
					firstTime = false;
				}

				if(startingNumber <= currentTask->endRange)
				{
					float xx = (2 * ((x + 0.5) * invWidth) - 1) * angle * aspectratio;
					float yy = (1 - 2 * ((y + 0.5) * invHeight)) * angle;
					Vec3<float> raydir(xx, yy, -1);
					raydir.normalize();
					*pixel = RecursiveRayTracer<float>::trace(Vec3<T>(0), raydir, currentTask->sphereListPointer, 0);
					startingNumber++;
				}
				else
				{
					currentTask->complitedArray[currentTask->index] = true;
					return NULL;
				}
			}
		}
		currentTask->complitedArray[currentTask->index] = true;
		return NULL;
		
	}
//
	static void ExcuteBagOfTasks()
	{
		srand(13);
		std::vector<Sphere<T> *> spheres;
		// position, radius, surface color, reflectivity, transparency, emission color
		spheres.push_back(new Sphere<float>(Vec3<float>(0, -10004, -20), 10000, Vec3<float>(0.2), 0, 0.0));
		spheres.push_back(new Sphere<float>(Vec3<float>(0, 0, -20), 4, Vec3<float>(1.00, 0.32, 0.36), 1, 0.5));
		spheres.push_back(new Sphere<float>(Vec3<float>(5, -1, -15), 2, Vec3<float>(0.90, 0.76, 0.46), 1, 0.0));
		spheres.push_back(new Sphere<float>(Vec3<float>(5, 0, -25), 3, Vec3<float>(0.65, 0.77, 0.97), 1, 0.0));
		spheres.push_back(new Sphere<float>(Vec3<float>(-5.5, 0, -15), 3, Vec3<float>(0.90, 0.90, 0.90), 1, 0.0));
		// light
		spheres.push_back(new Sphere<float>(Vec3<float>(0, 20, -30), 3, Vec3<float>(0), 0, 0, Vec3<float>(3)));
		time_t startTimer;
		time(&startTimer);
		std::cout << "start time is " << startTimer << std::endl;
		BagOfTasks<T> *bagOfTasks = new BagOfTasks<T>(spheres,  800, 600);
		bagOfTasks->execute();
		//render<float>(spheres);
		
	}
};

